
namespace Nutils 
{
    public class IShelfTab
    {
        public IShelfTab()
        {
        }

    }


    public class ShelfGUI
    {
        public _ShelfTab CreateTab;
        public _ShelfTab ManageTab;
        public _ConfigTab ConfigTab;

        private P4.MultiDepo _depo;

        public ShelfGUI()
        {
            _depo = new Nutils.P4.MultiDepo();
            CreateTab = new _ShelfTab(_depo);
            ManageTab = new _ShelfTab(_depo);
            ConfigTab = new _ConfigTab("config.xml");
        }

        public class _ConfigTab : IShelfTab
        {
            public System.Collections.Generic.List<P4Connection> P4Connections;
            public bool HasChanged;
            public string LocalShelfDir
            {
                get
                {
                    return Shelf.IShelf.sShelfRootDir;
                }
                set
                {
                    Shelf.IShelf.sShelfRootDir = value;
                }
            }
            public string ConfigFile;
            public int CurrentIndex;

            private P4Connection _GetSelected()
            {
                if (CurrentIndex >= 0 && CurrentIndex < P4Connections.Count)
                {
                    return P4Connections[CurrentIndex];
                }
                return null;
            }

            public string ConnectionName
            {
                get
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return "";

                    return p4Connection.ConnectionName;
                }
                set
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return;
                    if (p4Connection.ConnectionName != value)
                        HasChanged = true;

                    p4Connection.ConnectionName = value;
                }
            }
            public string User
            {
                get
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return "";

                    return p4Connection.User;
                }
                set
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return;
                    if (p4Connection.User != value)
                        HasChanged = true;

                    p4Connection.User = value;
                }
            }
            public string ClientSpec
            {
                get
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return "";

                    return p4Connection.ClientSpec;
                }
                set
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return;
                    if (p4Connection.ClientSpec != value)
                        HasChanged = true;

                    p4Connection.ClientSpec = value;
                }
            }
            public string Password
            {
                get
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return "";

                    return p4Connection.Password;
                }
                set
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return;
                    if (p4Connection.Password != value)
                        HasChanged = true;

                    p4Connection.Password = value;
                }
            }
            public string Depo
            {
                get
                {
                    P4Connection p4Connection = _GetSelected();
                    if (null == p4Connection)
                        return "";
                    return p4Connection.Depo;
                }
                set
                {
                    P4Connection p4Connection = _GetSelected();

                    if (null == p4Connection)
                        return;
                    if (p4Connection.Depo != value)
                        HasChanged = true;

                    p4Connection.Depo = value;
                }
            }

            public _ConfigTab(string configFile)
            {
                CurrentIndex = -1;
                try
                {
                    ReadConfig(ConfigFile = configFile);
                }
                catch (System.Exception ex)
                {
                    Nutils.Console.Error("Config file appears invalid. " + ex.Message);
                }
                HasChanged = false;
            }

            public P4Connection AddConnection()
            {
                P4Connections.Add(new P4Connection());
                HasChanged = true;
                return P4Connections[P4Connections.Count - 1];
            }

            public void DeleteConnection()
            {
                if (0 > CurrentIndex)
                {
                    return;
                }

                P4Connections.RemoveAt(CurrentIndex);
                HasChanged = true;
            }

            public void WriteConfig()
            {
                XML.Writer cWriter = Nutils.XML.OpenWriter_WaitTillUnlocked(ConfigFile);
                if (null == cWriter)
                {
                    return;
                }

                try
                {
                    cWriter.Formatting = System.Xml.Formatting.Indented;
                    cWriter.Indentation = 4;
                    cWriter.Namespaces = false;

                    cWriter.WriteStartDocument();
                    cWriter.WriteStartElement("root");

                    cWriter.WriteElementString("LocalShelfDir", LocalShelfDir);

                    foreach (P4Connection p4Connection in P4Connections)
                    {
                        cWriter.WriteStartElement("P4Connection");
                        p4Connection.Pack(cWriter);
                        cWriter.WriteEndElement();
                    }

                    cWriter.WriteEndDocument();
                }
                finally
                {
                    cWriter.Flush();
                    cWriter.Close();
                }
            }

            public void ReadConfig(string configFile)
            {
                P4Connections = new P4ConnectionList();

                XML.Tree xmlTree = XML.Parse(configFile);
                if (null == xmlTree)
                {
                    return;
                }
                
                // P4Connections
                foreach (XML.Tree node in xmlTree.ForEach("P4Connection"))
                {
                    P4Connection p4Connection = new P4Connection();
                    p4Connection.Parse(node);
                    P4Connections.Add(p4Connection);
                }

                // FileType mappings
                Nutils.File.Unpack(xmlTree);

                // Everything else
                LocalShelfDir = xmlTree.FindTextValue("LocalShelfDir", LocalShelfDir);
            }

            public class P4Connection
            {
                static int InstanceCount = 0;
                public string ConnectionName;
                public string User;
                public string ClientSpec;
                public string Password;
                public string Depo;

                public P4Connection()
                {
                    ConnectionName = string.Format("P4Connection{0}", InstanceCount);
                    User = "";
                    ClientSpec = "";
                    Password = "";
                    Depo = "";
                    ++InstanceCount;
                }

                override public string ToString()
                {
                    string sCrypt = Crypto.Encrypt(ConnectionName, 13);
                    string sDecrypt = Crypto.Decrypt(sCrypt, 13);
                    return ConnectionName;
                }


                public void Pack(System.Xml.XmlWriter cWriter)
                {
                    cWriter.WriteElementString("ConnectionName", ConnectionName);
                    cWriter.WriteElementString("User", User);
                    cWriter.WriteElementString("ClientSpec", ClientSpec);
                    cWriter.WriteElementString("Depo", Depo);

                    if (Password.Length > 0)
                    {

                        cWriter.WriteElementString("Password", Crypto.Encrypt(Password, 13));
                    }
                }

                public void Parse(XML.Tree xmlTree)
                {
                    ConnectionName = xmlTree.FindTextValue("ConnectionName", ConnectionName);
                    User = xmlTree.FindTextValue("User", User);
                    ClientSpec = xmlTree.FindTextValue("ClientSpec", ClientSpec);
                    Password = Crypto.Decrypt( xmlTree.FindTextValue("Password", Password), 13 );
                    Depo = xmlTree.FindTextValue("Depo", Depo);
                }
            }

            public class P4ConnectionList : System.Collections.Generic.List<P4Connection> { };
        }


        public bool Connect()
        {
            if (_depo.Connected)
            {
                _depo = new Nutils.P4.MultiDepo();
            }

            foreach (_ConfigTab.P4Connection p4Connection in ConfigTab.P4Connections)
            {
                string sMsg = string.Format("Connecting to \"{0}\" as \"{1}\" with \"{2}\"", p4Connection.Depo, p4Connection.User, p4Connection.ClientSpec);
                Nutils.Console.Notify(sMsg+".");
                try
                {
                    _depo.Connect(p4Connection.Depo, p4Connection.User, p4Connection.ClientSpec, p4Connection.Password);
                }
                catch (System.Exception ex)
                {
                    Nutils.Console.Exception(ex);
                }
            }

            return Connected;
        }

        public void QuickSync()
        {
            if (!Connected)
            {
                return;
            }

            foreach (P4.Depo depo in _depo.Depos)
            {
                depo.SyncToHead(true);
            }
        }

        public string[] Jobs()
        {
            if (Connected)
            {
                System.Collections.Generic.List<string> lJobNames = new System.Collections.Generic.List<string>();
                lJobNames.Add("<none>");
                foreach (P4.Job cJob in _depo.Jobs)
                {
                    lJobNames.Add(cJob.Name);
                }

                return lJobNames.ToArray();
            }

            return new string[] { "<not connected>" };
        }

        public object[] Shelves()
        {
            if (Connected)
            {
                return Shelf.IShelf.FindShelves();
            }

            return new object[] { "<not connected>" };
        }

        public string[] Changelists()
        {
            if (Connected)
            {
                System.Collections.Generic.List<string> lCLNames = new System.Collections.Generic.List<string>();
                foreach (P4.Changelist cCL in _depo.ChangeLists)
                {
                    lCLNames.Add(cCL.ChangeID);
                }

                return lCLNames.ToArray();
            }

            return new string[] { "<not connected>" };
        }

        public string[] CheckedOutFiles()
        {
            if (Connected)
            {
                System.Collections.Generic.List<string> lFiles = new System.Collections.Generic.List<string>();
                foreach (P4.Changelist cCL in _depo.ChangeLists)
                {
                    foreach (P4.CLFile cFile in cCL.Files)
                    {
                        lFiles.Add(cFile.DepoFile + " " + "#" + cFile.HaveRev);
                    }
                }
                return lFiles.ToArray();
            }
            return new string[] { };
        }

        public void Shelve(string[] lFiles, _ShelfTab cTab, bool bRelease)
        {
            Shelf.Shelver cShelf = new Shelf.Shelver(cTab.ShelfName);
            cShelf.sJobName = cTab.JobName;
            cShelf.sComment = cTab.Comment;

            foreach (P4.Changelist cCL in _depo.ChangeLists)
            {
                foreach (P4.CLFile cFile in cCL.Files)
                {
                    foreach (string sFile in lFiles)
                    {
                        if (sFile.Contains(cFile.DepoFile))
                        {
                            cShelf.AddFile(cFile);
                        }
                    }
                }
            }

            cShelf.Pack( _depo );
            if (bRelease)
            {
                cShelf.Release();
            }
        }

        public bool Connected { get { return _depo.Connected; } }

        public class _ShelfTab
        {
            public bool IsPublic;
            public bool DoAutoResolve;
            public string TimeStamp;
            public string Comment;
            public string JobName;
            public string ShelfName;
            public string[] Files;
            public Shelf.Unshelver _Shelf;
            public P4.MultiDepo _depo;
            public string ShelfLocalPathName { get { return Shelf.IShelf.sShelfRootDir + ShelfName + ".shelf"; } }

            public _ShelfTab(P4.MultiDepo cDepo)
            {
                _depo = cDepo;
                _Shelf = null;
                IsPublic = false;
                DoAutoResolve = false;
                Files = new string[0];
            }

            public bool Unpack()
            {
                Nutils.Console.Notify("Unpacking...");
                try
                {
                    _Shelf = new Shelf.Unshelver(ShelfName);
                    _Shelf.Unpack();
                }
                catch (System.Exception ex)
                {
                    Nutils.Console.Notify("End Unpack (Failure)");
                    Nutils.Console.Error(ex.Message);
                    Nutils.Console.Error(ex.StackTrace);
                    return false;
                }

                Comment = _Shelf.sComment;
                JobName = _Shelf.sJobName;

                System.Collections.Generic.List<string> lTempFiles = new System.Collections.Generic.List<string>();
                foreach (Shelf.File cShelfFile in _Shelf.lFiles)
                {
                    lTempFiles.Add(cShelfFile.sFileNameInDepo + "#" + cShelfFile.sRev);
                }

                Files = lTempFiles.ToArray();

                Nutils.Console.Notify("...Unpacking Done");
                return Files.Length > 0;
            }

            public void Update()
            {
                Nutils.Console.Notify("Updating...");
                _Shelf.sComment = Comment;
                _Shelf.sJobName = JobName;
                _Shelf.Update(_depo);
                Nutils.Console.Notify("... Done Updating");
            }

            public void Inflate()
            {
                Nutils.Console.Notify("Inflating...");
                _Shelf.Inflate(_depo, DoAutoResolve);
                Nutils.Console.Notify("...Done Inflating");
            }

            public void Delete()
            {
                Nutils.Console.Notify("Deleting...");
                _Shelf.Delete();

                ShelfName = "";
                IsPublic = false;
                TimeStamp = "";
                Comment = "";
                JobName = "";
                Files = new string[0];
                _Shelf = null;
                Nutils.Console.Notify("...Deleting Done");
            }
        }

    }
}